
/**
  * @file thread_container.h
  * < This is a thread container, it can be invoke some different function.>
  *
  * Copyright (c) by <lid/>
  * @author jingwei.guan@hotmail.com
  * modify history:
  * date     version     author     content
  * 1/8/2011  0.0.1       lid       provide thread manager
 */

#ifndef _ad17f565_bcac_4e9f_87fc_84d179146274__THREAD_CONTAINER_H__
#define _ad17f565_bcac_4e9f_87fc_84d179146274__THREAD_CONTAINER_H__

#include <list>
#include <assert.h>
#include "typedefine.h"
#include "mutex.h"

// thread
#if defined(JELLY_WIN32) || defined(JELLY_WINCE)
#include "win_thread.h"
#elif defined(JELLY_LINUX)
#include "linux_thread.h"
#endif

namespace thread
{
	template < typename Thread,typename LockPolicy>
	class ThreadContainer
	{
	public:
		typedef Thread thread_type;
		enum
		{
			threadpool_parameter = -99,
			threadpool_noavailable,
			threadpool_overmax,
			threadpool_nothread,
			threadpool_createthread_error,
			threadpool_error = -1,
			threadpool_successed = 1
		};
	private:
		enum
		{
			thread_free = 0,
			thread_busy = 1
		};
		struct ThreadInfo
		{
			ThreadInfo()
				:flag(thread_free)
				,thread(NULL)
			{
			}
			uint32_t flag;
			thread_type* thread;
		};
		typedef std::list<ThreadInfo> threads_type;
		struct AvailablePolicy
		{
			bool operator ()(ThreadInfo* info)
			{
				return thread_free == info->flag? true:false;
			}
		};
		struct NotConcernPolicy
		{
			bool operator ()(ThreadInfo* info)
			{
				assert(NULL!=info);
				return true;
			}
		};
	public:
		ThreadContainer()
			:max_(0)
		{
		}

		~ThreadContainer()
		{
			_cleanThread((uint32_t)threads_.size(),NotConcernPolicy());
		}

		int32_t create(uint32_t init,uint32_t max)
		{
			if (0==init || max<init)
			{
				return threadpool_parameter;
			}

			max_ = max;
			int32_t ret = threadpool_successed;
			if (threads_.empty())
			{
				return _generateThread(init);
			}
			else
			{
				uint32_t size = (uint32_t)threads_.size();
				if (size>init)
				{
					_cleanThread((uint32_t)size-init,AvailablePolicy());
				}
				else
				{
					ret = _generateThread((uint32_t)size - init);
				}
			}
			return ret;
		}
		thread_type* available()
		{
			ThreadInfo* info = _available();
			return NULL!=info? info->thread:NULL;
		}
	private:
		ThreadContainer(const ThreadContainer&);
		ThreadContainer& operator = (const ThreadContainer&);
		ThreadInfo* _available()
		{
			ThreadInfo* p = _findFree(AvailablePolicy());
			if(NULL!=p)
			{
				return p;
			}
			return _generateThread(1)>0?_findFree(AvailablePolicy()):NULL;
		}
		void _beAvailable(thread_type* t)
		{
			typename LockPolicy::innerLock lock(&lock_);
			for (typename threads_type::iterator iter = threads_.begin();
				iter!=threads_.end();++iter)
			{
				if (t == (*iter).thread )
				{
					(*iter).flag = thread_free;
					return;
				}
			}
		}
		template<typename Behavior /*= AvailablePolicy*/>
		ThreadInfo* _findFree(Behavior behavior)
		{
			typename LockPolicy::innerLock lock(&lock_);
			for (typename threads_type::iterator iter = threads_.begin();
				iter!=threads_.end();++iter)
			{
				if (behavior(&(*iter)))
				{
					(*iter).flag = thread_busy;
					return &(*iter);
				}
			}
			return NULL;
		}

		template<typename Behavior>
		void _cleanThread(uint32_t n,Behavior behavior)
		{
			typename LockPolicy::innerLock lock(&lock_);
			uint32_t count = 0;
			for (;;)
			{
				for (typename threads_type::iterator iter = threads_.begin();iter!=threads_.end();)
				{
					if (behavior(&(*iter)))
					{
						(*iter).thread->stop();
						delete (*iter).thread;
						(*iter).thread = NULL;
						++count;
						iter = threads_.erase(iter);
					}
					else
					{
						++iter;
					}
					if(count>=n)
					{
						return;
					}
				}
			}
		}
		int32_t _generateThread( uint32_t init )
		{
			typename LockPolicy::innerLock lock(&lock_);
			if (threads_.size()+init >= max_)
			{
				return threadpool_overmax;
			}
			ThreadInfo t;
			bool ret = false;
			for (uint32_t i=0;i<init;++i)
			{
				t.thread = new thread_type;
				if (NULL==t.thread)
				{
					return threadpool_error;
				}
				t.thread->notice_container_delegate = std::make_pair(this,&ThreadContainer::_beAvailable);
				ret = t.thread->create();
				if(!ret)
				{
				    return threadpool_createthread_error;
				}
				threads_.push_back(t);
			}
			return threadpool_successed;
		}

	private:
		threads_type threads_;
		uint32_t max_;
		LockPolicy lock_;
	};
}

#endif //_ad17f565_bcac_4e9f_87fc_84d179146274__THREAD_CONTAINER_H__
